home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / c2man-2.0pl33.lha / c2man-2.0 / c2man.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-24  |  21.5 KB  |  892 lines

  1. /* $Id: c2man.c,v 2.0.1.35 1994/10/06 06:05:26 greyham Exp $
  2.  *
  3.  * C Manual page generator.
  4.  * Reads C source code and outputs manual pages.
  5.  */
  6. #include <ctype.h>
  7. #include <errno.h>
  8.  
  9. #include "c2man.h"
  10. #include "enum.h"
  11. #include "strconcat.h"
  12. #include "strappend.h"
  13. #include "manpage.h"
  14. #include "output.h"
  15. #include "patchlevel.h"
  16.  
  17. #ifdef I_FCNTL
  18. #include <fcntl.h>
  19. #endif
  20.  
  21. #ifdef I_SYS_FILE
  22. #include <sys/file.h>
  23. #endif
  24.  
  25. #include <sys/stat.h>
  26. #include <signal.h>
  27.  
  28. /* getopt declarations */
  29. extern int getopt();
  30. extern char *optarg;
  31. extern int optind;
  32.  
  33. /* lex declarations */
  34. extern FILE *yyin;    /* lex input stream */
  35.  
  36. /* Name of the program */
  37. const char *progname = "c2man";
  38.  
  39. /* Program options */
  40.  
  41. /* TRUE if static declarations are also output. */
  42. boolean static_out = FALSE;
  43.  
  44. /* TRUE if variable declarations are output. */
  45. boolean variables_out = FALSE;
  46.  
  47. /* TRUE if formal parameter promotion is enabled. */
  48. boolean promote_param = TRUE;
  49.  
  50. /* String output before prototype declaration specifiers */
  51. const char *decl_spec_prefix = "";
  52.  
  53. /* String output before prototype declarator */
  54. const char *declarator_prefix = " ";
  55.  
  56. /* String output after prototype declarator */
  57. const char *declarator_suffix = "\n";
  58.  
  59. /* String output before the first parameter in a function prototype */
  60. const char *first_param_prefix = "\n\t";
  61.  
  62. /* String output before each subsequent parameter in a function prototype */
  63. const char *middle_param_prefix = "\n\t";
  64.  
  65. /* String output after the last parameter in a function prototype */
  66. const char *last_param_suffix = "\n";
  67.  
  68. /* Directory to write output files in */
  69. char *output_dir = NULL;
  70.  
  71. /* Name of the manual */
  72. char *manual_name = NULL;
  73.  
  74. /* Section for manual page */
  75. const char *manual_section = NULL;
  76.  
  77. /* prefix for generated #include lines */
  78. char *header_prefix = NULL;
  79.  
  80. /* list of include file specified by user */
  81. IncludeFile *first_include;
  82. static IncludeFile **last_next_include = &first_include;
  83.  
  84. /* list of excluded sections specified by user */
  85. ExcludeSection *first_excluded_section;
  86. static ExcludeSection **last_next_excluded_section = &first_excluded_section;
  87.  
  88. /* do we group related stuff into one file? */
  89. boolean group_together;
  90.  
  91. /* was terse description read from file or command line option? */
  92. boolean terse_specified;
  93.  
  94. /* terse description when grouped together */
  95. char *group_terse = NULL;
  96.  
  97. /* should we always document parameters, even if it's only "Not Documented" */
  98. boolean always_document_params = TRUE;
  99.  
  100. /* default output info for each object type */
  101. struct Output_Object_Info output_object[_OBJECT_NUM] =
  102. {
  103. #if 0
  104.     {'c', "class"},
  105.     {'s', "struct"},
  106.     {'e', "enum"},
  107.     {'t', "typedef"},
  108. #endif
  109.     {'f', "function"},
  110.     {'v', "variable"},
  111.     {'F', "static function"},
  112.     {'V', "static variable"}
  113. };
  114.  
  115. /* Include file directories */
  116. #ifdef MSDOS
  117. int num_inc_dir = 1;
  118. const char *inc_dir[MAX_INC_DIR] = { ".\\" };
  119. #else
  120. int num_inc_dir = 2;
  121. const char *inc_dir[MAX_INC_DIR] = { "./", "/usr/include/" };
  122. #endif
  123.  
  124. /* total number of errors encountered */
  125. int errors;
  126.  
  127. /* name of the base file being processed; NULL = stdin */
  128. const char *basefile;
  129. Time_t basetime;    /* modification time of base file */
  130. boolean inbasefile;    /* are we parsing in that base file? */
  131.  
  132. /* is the base file a header file? */
  133. boolean header_file;
  134.  
  135. /* use nroff output by default */
  136. struct Output *output = &nroff_output;
  137.  
  138. /* should we generate the output file named after the input file? */
  139. boolean use_input_name = FALSE;
  140.  
  141. /* should we generate embeddable files? */
  142. boolean make_embeddable = FALSE;
  143.  
  144. #define USE_CPP
  145. #ifdef USE_CPP
  146. const char *cpp_cmd = CPP_FILE_COM;
  147. #if defined(MSDOS)
  148. #include "popen.h"
  149. #define popen(c,m)    os_popen(c,m)
  150. #define pclose(f)    os_pclose(f)
  151. #else
  152. #if defined (_MSC_VER)
  153. #define popen(c,m)    _popen(c,m)
  154. #define pclose(f)    _pclose(f)
  155. #endif
  156. #endif
  157. #endif
  158.  
  159. boolean verbose = FALSE;
  160.  
  161. /* can cpp read standard input? */
  162. static boolean cppcanstdin
  163. #ifdef CPP_CAN_STDIN
  164.                 = 1
  165. #endif
  166. ;
  167. /* does cpp ignore header files */
  168. static boolean cppignhdrs
  169. #ifdef CPP_IGN_HDRS
  170.                 = 1
  171. #endif
  172. ;
  173.  
  174. /* nifty little function for handling I/O errors */
  175. void my_perror(action, filename)
  176. const char *action, *filename;
  177. {
  178.     int err = errno;
  179.     fprintf(stderr,"%s: %s ", progname, action);
  180.     errno = err;
  181.     perror(filename);
  182. }
  183.  
  184. /* write the #include lines as specified by the user */
  185. void print_includes(f)
  186. FILE *f;
  187. {
  188.     IncludeFile *incfile;
  189.     
  190.     for (incfile = first_include; incfile; incfile=incfile->next)
  191.     {
  192.     char *name = incfile->name;
  193.     boolean surrounded = *name == '"' || *name == '<';
  194.     
  195.     fputs("#include ", f);
  196.     if (!surrounded)    fputc('<',f);
  197.     fputs(name, f);
  198.     if (!surrounded)    fputc('>',f);
  199.     fputc('\n',f);
  200.     }
  201. }
  202.  
  203. void outmem()
  204. {
  205.     fprintf(stderr,"%s: Out of memory!\n", progname);
  206.     exit(1);
  207. }
  208.  
  209. #ifndef DBMALLOC
  210. void *safe_malloc(size)
  211. size_t size;
  212. {
  213.     void *mem;
  214.  
  215.     if ((mem = (void *)malloc(size)) == NULL)
  216.     outmem();
  217.  
  218.     return mem;
  219. }
  220. #endif
  221.  
  222. /* Replace any character escape sequences in a string with the actual
  223.  * characters.  Return a pointer to malloc'ed memory containing the result.
  224.  * This function knows only a few escape sequences.
  225.  */
  226. static char *
  227. escape_string (src)
  228. char *src;
  229. {
  230.     char *result, *get, *put;
  231.  
  232.     result = strduplicate(src);
  233.     put = result;
  234.     get = src;
  235.     while (*get != '\0') {
  236.     if (*get == '\\') {
  237.         switch (*(++get)) {
  238.         case 'n':
  239.         *put++ = '\n';
  240.         ++get;
  241.         break;
  242.         case 't':
  243.         *put++ = '\t';
  244.         ++get;
  245.         break;
  246.         default:
  247.         if (*get != '\0')
  248.             *put++ = *get++;
  249.         }
  250.     } else {
  251.         *put++ = *get++;
  252.     }
  253.     }
  254.     *put = *get;
  255.     return result;
  256. }
  257.  
  258. /* Output usage message and exit.
  259.  */
  260. static void
  261. usage ()
  262. {
  263.     int i;
  264.  
  265.     fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
  266.     fputs(" -o directory\twrite output files in directory\n",stderr);
  267.     fputs(" -p\t\tdisable prototype promotion\n", stderr);
  268.     fputs(" -s\t\toutput static declarations\n", stderr);
  269.     fputs(" -v\t\toutput variable declarations\n", stderr);
  270.     fputc('\n', stderr);
  271.     fputs(" -i incfile\n", stderr);
  272.     fputs(" -i \"incfile\"\n", stderr);
  273.     fputs(" -i <incfile>\tadd #include for incfile to SYNOPSIS\n",
  274.                                     stderr);
  275.     fputc('\n', stderr);
  276.     fputs(" -H prefix\tspecify prefix for #include in SYNOPSIS\n", stderr);
  277.     fputc('\n', stderr);
  278.     fputs(" -g\n", stderr);
  279.     fputs(" -G terse\tgroup info from each file into a single page\n",
  280.                                     stderr);
  281.     fputs(" -e\t\tmake embeddable files\n", stderr);
  282.     fputc('\n', stderr);
  283.     fputs(" -l ", stderr);
  284. #ifdef HAS_LINK
  285.     fputs("h|", stderr);
  286. #endif
  287. #ifdef HAS_SYMLINK
  288.     fputs("s|", stderr);
  289. #endif
  290.     fputs("f|n|r\t", stderr);
  291.     fputs("linking for grouped pages: ", stderr);
  292. #ifdef HAS_LINK
  293.                   fputs("hard, ", stderr);
  294. #endif
  295. #ifdef HAS_SYMLINK
  296.                     fputs("soft, ", stderr);
  297. #endif
  298.                     fputs("file, none or remove\n", stderr);
  299.     fputs(" -n\t\tName output file after input source file\n", stderr);
  300.     fputs(" -L\t\tLazy: Be silent about undocumented parameters\n",
  301.                                     stderr);
  302.     fputs(" -T n|l|h|t[,options]\tselect typesetting output format: nroff, LaTeX, HTML or TeXinfo\n",
  303.                                     stderr);
  304.     nroff_output.print_options();
  305.     latex_output.print_options();
  306.     html_output.print_options();
  307.     texinfo_output.print_options();
  308.  
  309.     fputs(" -M name\tset name of the manual in which the page goes\n",
  310.                                     stderr);
  311.     fputs(" -x section\texclude section from ouput\n", stderr);
  312.     fputc('\n', stderr);
  313.     fputs(" -D name[=value]\n", stderr);
  314.     fputs(" -U name\n", stderr);
  315.     fputs(" -I directory\tC preprocessor options\n", stderr);
  316.     fputc('\n', stderr);
  317.     fputs(" -F template\tset prototype template in the form ", stderr);
  318.                     fputs("\"int f (a, b)\"\n",stderr);
  319.     fputs(" -P preprocessor\tAlternate C preprocessor ", stderr);
  320.                     fputs("(e.g., \"gcc -E -C\")\n", stderr);
  321.     fputs(" -V\t\tbe verbose and print version information\n", stderr);
  322.     fputs(" -S section\tset the section for the manual page (default = 3)\n",
  323.                                     stderr);
  324.     fputs(" -O ", stderr);
  325.     for (i = 0; i < _OBJECT_NUM; i++)
  326.     fputc(output_object[i].flag, stderr);
  327.     fputs("[subdir][.ext]", stderr);
  328.     fputs("\tOutput control over different object types:\n\t\t", stderr);
  329.     for (i = 0; i < _OBJECT_NUM; i++)
  330.     {
  331.     fputs(output_object[i].name, stderr);
  332.     if (i <= _OBJECT_NUM - 2)
  333.         fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  334.     }
  335.     fputs(".\n", stderr);
  336.     exit(1);
  337. }
  338.  
  339. /* name of the temporary file; kept here so we can blast it if hit with ctrl-C
  340.  */
  341. static char temp_name[20];
  342. Signal_t (*old_interrupt_handler)();
  343.  
  344. /* ctrl-C signal handler for use when we have a temporary file */
  345. static Signal_t interrupt_handler(sig)
  346. int sig;
  347. {
  348.     unlink(temp_name);
  349.     exit(128 + sig);
  350. }
  351.  
  352. /* open a unique temporary file.
  353.  * To be universally accepted by cpp's, the file's name must end in .c; so we
  354.  * can't use mktemp, tmpnam or tmpfile.
  355.  * returns an open stream & sets ret_name to the name.
  356.  */
  357. FILE *open_temp_file()
  358. {
  359.     int fd;
  360.     long n = getpid();
  361.     FILE *tempf;
  362.     boolean remove_temp_file();
  363.  
  364.     /* keep generating new names until we hit one that does not exist */
  365.     do
  366.     {
  367.     /* ideally we'd like to put the temporary file in /tmp, but it must go
  368.      * in the current directory because when cpp processes a #include, it
  369.      * looks in the same directory as the file doing the include; so if we
  370.      * use /tmp/blah.c to fake reading fred.h via `#include "fred.h"', cpp
  371.      * will look for /tmp/fred.h, and fail.
  372.      */
  373.     sprintf(temp_name,"c2man%ld.c",n++ % 1000000);
  374.     }
  375.     while((fd =
  376. #ifdef HAS_OPEN3
  377.     open(temp_name,O_WRONLY|O_CREAT|O_EXCL,0666)
  378. #else
  379.     creat(temp_name,O_EXCL|0666)        /* do it the old way */
  380. #endif
  381.                         ) == -1
  382.                             && errno == EEXIST);
  383.  
  384.     /* install interrupt handler to remove the temporary file */
  385.     old_interrupt_handler = signal(SIGINT, interrupt_handler);
  386.  
  387.     /* convert it to a stream */
  388.     if ((fd == -1 && errno != EEXIST) || (tempf = fdopen(fd, "w")) == NULL)
  389.     {
  390.     my_perror("error fdopening temp file",temp_name);
  391.     remove_temp_file();
  392.     return NULL;
  393.     }
  394.  
  395.     return tempf;
  396. }
  397.  
  398. /* remove the temporary file & restore ctrl-C handler.
  399.  * returns FALSE in the event of failure.
  400.  */
  401. boolean remove_temp_file()
  402. {
  403.     int ok = unlink(temp_name) == 0;    /* this should always succeed */
  404.     signal(SIGINT, old_interrupt_handler);
  405.     return ok;
  406. }
  407.  
  408. /* process the specified source file through the pre-processor.
  409.  * This is a lower level routine called by both process_stdin and process_file
  410.  * to actually get the work done once any required temporary files have been
  411.  * generated.
  412.  */
  413. int process_file_directly(base_cpp_cmd, name)
  414. const char *base_cpp_cmd;
  415. const char *name;
  416. {
  417.     char *full_cpp_cmd;
  418.  
  419. #ifdef DEBUG
  420.     fprintf(stderr,"process_file_directly: %s, %s\n", base_cpp_cmd, name);
  421. #endif
  422.  
  423. #ifdef USE_CPP
  424.     full_cpp_cmd = strconcat(base_cpp_cmd, " ", name, NULLCP);
  425.     if (verbose)
  426.     fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  427.  
  428.     if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  429.     my_perror("error running", base_cpp_cmd);
  430.     free(full_cpp_cmd);
  431.     return 0;
  432.     }
  433. #else
  434.     if (verbose)    fprintf(stderr,"%s: reading %s\n", progname, name);
  435.     if (name && freopen(name, "r", yyin) == NULL)
  436.     {
  437.     my_perror("cannot open", name);
  438.     return 0;
  439.     }
  440. #endif
  441.  
  442.     parse_file(name);
  443.  
  444. #ifdef USE_CPP
  445.     free(full_cpp_cmd);
  446.     if (pclose(yyin) & 0xFF00)
  447.     return 0;
  448. #else
  449.     if (fclose(yyin))
  450.     {
  451.     my_perror("error closing", name);
  452.     return 0;
  453.     }
  454. #endif
  455.  
  456.     return !errors;
  457. }
  458.  
  459. /* process a specified file */
  460. int process_file(base_cpp_cmd, name)
  461. const char *base_cpp_cmd;
  462. const char *name;
  463. {
  464.     char *period;
  465.     struct stat statbuf;
  466.     
  467. #ifdef DEBUG
  468.     fprintf(stderr,"process_file: %s, %s\n", base_cpp_cmd, name);
  469. #endif
  470.     basefile = name;
  471.     header_file = (period = strrchr(name,'.')) &&
  472.                     (period[1] == 'h' || period[1] == 'H');
  473.  
  474.     /* use the file's date as the date in the manual page */
  475.     if (stat(name,&statbuf) != 0)
  476.     {
  477.     my_perror("can't stat", name);
  478.     return 0;
  479.     }
  480.     basetime = statbuf.st_mtime;
  481.  
  482.     /* should we do this via a temporary file?
  483.      * Only if it's a header file and either CPP ignores them, or the user
  484.      * has specified files to include.
  485.      *
  486.      * For HP/Apollo (SR10.3, CC 6.8), we must always use a temporary file,
  487.      * because its compiler recognizes the special macro "__attribute(p)",
  488.      * which we cannot redefine in the command line because it has parameters.
  489.      */
  490. #ifndef apollo
  491.     if (header_file && (cppignhdrs || first_include))
  492. #endif
  493.     {
  494.     FILE *tempf;
  495.     int ret;
  496.  
  497.     if (verbose)
  498.         fprintf(stderr, "%s: preprocessing via temporary file\n", progname);
  499.  
  500.     if ((tempf = open_temp_file()) == NULL)
  501.         return 0;
  502.  
  503.     print_includes(tempf);
  504.     if (verbose)    print_includes(stderr);
  505.  
  506. #ifdef apollo
  507.     fprintf(tempf,"#define __attribute(p)\n", basefile);
  508. #endif
  509.     fprintf(tempf,"#include \"%s\"\n", basefile);
  510.     if (verbose)    fprintf(stderr,"#include \"%s\"\n", basefile);
  511.  
  512.     if (fclose(tempf) == EOF)
  513.     {
  514.         my_perror("error closing temp file", temp_name);
  515.         remove_temp_file();
  516.         return 0;
  517.     }
  518.  
  519.     /* since we're using a temporary file, it's not the base file */
  520.     inbasefile = 0;
  521.     ret = process_file_directly(base_cpp_cmd, temp_name);
  522.     remove_temp_file();
  523.     return ret;
  524.     }
  525.  
  526.     /* otherwise, process it directly */
  527.     inbasefile = 1;
  528.  
  529.     return process_file_directly(base_cpp_cmd,name);
  530. }
  531.  
  532. /* process the thing on the standard input */
  533. int process_stdin(base_cpp_cmd)
  534. const char *base_cpp_cmd;
  535. {
  536.     if (isatty(fileno(stdin)))
  537.     fprintf(stderr,"%s: reading standard input\n", progname);
  538.  
  539.     header_file = 0;    /* assume it's not since it's from stdin */
  540.     basefile = NULL;
  541.  
  542.     /* use the current date in the man page */
  543.     basetime = time((Time_t *)NULL);
  544.  
  545.     inbasefile = 1;        /* reading stdin, we start in the base file */
  546.  
  547.     /* always use a temp file if the preprocessor can't read stdin, otherwise
  548.      * only use one if the user specified files for inclusion.
  549.      */
  550.     if (!cppcanstdin || first_include)    /* did user specify include files? */
  551.     {
  552.         FILE *tempf;
  553.     int c, ret;
  554.  
  555.     if (verbose)
  556.         fprintf(stderr,"%s: reading stdin to a temporary file\n", progname);
  557.  
  558.     if ((tempf = open_temp_file()) == NULL)
  559.         return 0;
  560.  
  561.     print_includes(tempf);
  562.     if (verbose)    print_includes(stderr);
  563.     fprintf(tempf,"#line 1 \"stdin\"\n");
  564.  
  565.     while ((c = getchar()) != EOF)
  566.         putc(c,tempf);
  567.  
  568.     if (fclose(tempf) == EOF)
  569.     {
  570.         my_perror("error closing temp file", temp_name);
  571.         remove_temp_file();
  572.         return 0;
  573.     }
  574.     ret = process_file_directly(base_cpp_cmd, temp_name);
  575.     remove_temp_file();
  576.     return ret;
  577.     }
  578.     else
  579.     {
  580.     char *full_cpp_cmd = strconcat(base_cpp_cmd," ", CPP_STDIN_FLAGS,
  581.                                    NULLCP);
  582.     
  583.     if (verbose)
  584.         fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  585.     
  586.     if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  587.         my_perror("error running", full_cpp_cmd);
  588.         return 0;
  589.     }
  590.     
  591.     parse_file(basefile);
  592.     
  593.     free(full_cpp_cmd);
  594.     if (pclose(yyin) & 0xFF00)
  595.         return 0;
  596.     
  597.     return !errors;
  598.     }
  599. }
  600.  
  601. int
  602. main (argc, argv)
  603. int argc;
  604. char **argv;
  605. {
  606.     int i, c, ok = 0;
  607.     char *s, cbuf[2];
  608.     const char *base_cpp_cmd;
  609.     IncludeFile *includefile;
  610.     ExcludeSection *excludesection;
  611.     char *cpp_opts;
  612.     const char *default_section = "3";
  613. #ifdef HAS_LINK
  614.     enum LinkType link_type = LINK_HARD;    /* for -g/G */
  615. #else
  616.     enum LinkType link_type = LINK_FILE;
  617. #endif
  618.  
  619. #ifdef YYDEBUG
  620.     extern int yydebug;
  621. #endif
  622.  
  623.     /* initialise CPP options with -D__C2MAN__ */
  624.     cbuf[0] = VERSION + '0';
  625.     cbuf[1] = '\0';
  626. #ifdef VMS
  627.     cpp_opts = strconcat("-\"D__C2MAN__=", cbuf, "\"",NULLCP);
  628. #else
  629.     cpp_opts = strconcat("-D__C2MAN__=", cbuf, NULLCP);
  630. #ifdef NeXT
  631.     cpp_opts = strappend(cpp_opts, " -D_NEXT_SOURCE", NULLCP);
  632. #endif /* !NeXT */
  633. #endif /* !VMS  */
  634.  
  635.     /* Scan command line options. */
  636.     while ((c = getopt(argc, argv, "P:D:F:I:psU:Vvo:eM:H:G:gi:x:S:l:LT:nO:"))
  637.                                     != EOF)
  638.     {
  639.     switch (c) {
  640.     case 'I':
  641.     case 'D':
  642.     case 'U':
  643.         cbuf[0] = c; cbuf[1] = '\0';
  644.         if (cpp_opts)
  645.         cpp_opts = strappend(cpp_opts," -",cbuf,optarg,NULLCP);
  646.         else
  647.         cpp_opts = strconcat("-",cbuf,optarg,NULLCP);
  648.         break;
  649.     case 'P':
  650.         cpp_cmd = optarg;
  651.  
  652.         /* with no better info to go on, we have to assume that this
  653.          * preprocessor is minimally capable.
  654.          */
  655.         cppcanstdin = 0;
  656.         cppignhdrs = 1;
  657.         break;
  658.     case 'G':
  659.         group_terse = optarg;
  660.         terse_specified = TRUE;
  661.         /* FALLTHROUGH */
  662.     case 'g':
  663.         group_together = TRUE;
  664.         break;
  665.     case 'F':
  666.         s = escape_string(optarg);
  667.  
  668.         decl_spec_prefix = s;
  669.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  670.         if (*s == '\0') usage();
  671.         *s++ = '\0';
  672.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  673.         if (*s == '\0') usage();
  674.  
  675.         declarator_prefix = s;
  676.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  677.         if (*s == '\0') usage();
  678.         *s++ = '\0';
  679.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  680.         if (*s == '\0') usage();
  681.  
  682.         declarator_suffix = s;
  683.         while (*s != '\0' && *s != '(') ++s;
  684.         if (*s == '\0') usage();
  685.         *s++ = '\0';
  686.  
  687.         first_param_prefix = s;
  688.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  689.         if (*s == '\0') usage();
  690.         *s++ = '\0';
  691.         while (*s != '\0' && *s != ',') ++s;
  692.         if (*s == '\0') usage();
  693.  
  694.         middle_param_prefix = ++s;
  695.         while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  696.         if (*s == '\0') usage();
  697.         *s++ = '\0';
  698.         while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  699.         if (*s == '\0') usage();
  700.  
  701.         last_param_suffix = s;
  702.         while (*s != '\0' && *s != ')') ++s;
  703.         *s = '\0';
  704.  
  705.         break;
  706.     case 'p':
  707.         promote_param = FALSE;
  708.         break;
  709.     case 's':
  710.         static_out = TRUE;
  711.         break;
  712.     case 'V':
  713.         verbose = TRUE;
  714.         fprintf(stderr, "%s: Version %d, Patchlevel %d\n",
  715.                     progname, VERSION, PATCHLEVEL);
  716.         break;
  717.     case 'v':
  718.         variables_out = TRUE;
  719.         break;
  720.     case 'o':
  721.         output_dir = optarg;
  722.         break;
  723.     case 'M':
  724.         manual_name = optarg;
  725.         break;
  726.     case 'H':
  727.         header_prefix = optarg;
  728.         break;
  729.     case 'i':
  730.         *last_next_include = includefile =
  731.                 (IncludeFile *)safe_malloc(sizeof *includefile);
  732.         includefile->name = optarg;
  733.         includefile->next = NULL;
  734.         last_next_include = &includefile->next;
  735.         break;
  736.     case 'x':
  737.         *last_next_excluded_section = excludesection =
  738.                 (ExcludeSection *)safe_malloc(sizeof *excludesection);
  739.         excludesection->name = optarg;
  740.         excludesection->next = NULL;
  741.         last_next_excluded_section = &excludesection->next;
  742.         break;
  743.     case 'S':
  744.         manual_section = optarg;
  745.         break;
  746.     case 'l':
  747.         switch(optarg[0])
  748.         {
  749. #ifdef HAS_LINK
  750.         case 'h':    link_type = LINK_HARD;    break;
  751. #endif
  752. #ifdef HAS_SYMLINK
  753.         case 's':    link_type = LINK_SOFT;    break;
  754. #endif
  755.         case 'f':    link_type = LINK_FILE;    break;
  756.         case 'n':    link_type = LINK_NONE;    break;
  757.         case 'r':    link_type = LINK_REMOVE;break;
  758.         default:    usage();
  759.         }
  760.         break;
  761.     case 'e':
  762.         make_embeddable = TRUE;
  763.         break;
  764.     case 'n':
  765.         use_input_name = TRUE;
  766.         break;
  767.     case 'L':
  768.         always_document_params = FALSE;
  769.         break;
  770.     case 'T':
  771.         switch(optarg[0])
  772.         {
  773.         case 'n':    output = &nroff_output;    break;
  774.         case 'l':    output = &latex_output;    default_section = "tex";
  775.             break;
  776.         case 't':    output = &texinfo_output; default_section = "texi";
  777.             break;
  778.         case 'h':    output = &html_output; default_section = "html";
  779.             break;
  780.         default:    usage();
  781.         }
  782.         s = strtok(&optarg[1], ",");
  783.         if (s && *output->parse_option == NULL) usage();
  784.         while(s)
  785.         {
  786.           if (output->parse_option(s)) usage();
  787.           s = strtok(NULL, ",");
  788.         }
  789.         break;
  790.     case 'O':
  791.         for (i = 0; i < _OBJECT_NUM; i++)
  792.         if (output_object[i].flag == optarg[0])
  793.             break;
  794.  
  795.         if (i == _OBJECT_NUM)
  796.         {
  797.         fprintf(stderr,"%s: -O option must specify one of:\n\t",
  798.                                 progname);
  799.         for (i = 0; i < _OBJECT_NUM; i++)
  800.         {
  801.             fprintf(stderr,"%c (%s)", output_object[i].flag,
  802.             output_object[i].name);
  803.             if (i <= _OBJECT_NUM - 2)
  804.             fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  805.         }
  806.         fprintf(stderr, ".\n");
  807.         exit(1);
  808.         }
  809.  
  810.         if ((s = strchr(++optarg,'.')))    /* look for an extension */
  811.         {
  812.         output_object[i].subdir = alloc_string(optarg, s);
  813.         output_object[i].extension = strduplicate(s+1);
  814.         }
  815.         else
  816.         output_object[i].subdir = strduplicate(optarg);
  817.  
  818.         break;
  819.     case '?':
  820.     default:
  821.         usage();
  822.     }
  823.     }
  824.  
  825.     /* make sure we have a manual section */
  826.     if (manual_section == NULL)    manual_section = default_section;
  827.  
  828. #ifdef MALLOC_DEBUG
  829.     getchar();    /* wait so we can start up NeXT MallocDebug tool */
  830. #endif
  831. #ifdef YYDEBUG
  832.     yydebug = 1;
  833. #endif
  834.  
  835.     if (cpp_opts)
  836.     {
  837.     base_cpp_cmd = strconcat(cpp_cmd, " ", cpp_opts, NULLCP);
  838.     free(cpp_opts);
  839.     }
  840.     else
  841.     base_cpp_cmd = cpp_cmd;
  842.  
  843.     if (optind == argc) {
  844.     if (use_input_name)
  845.     {
  846.         fprintf(stderr,"%s: %s\n", progname,
  847.         "cannot name output after input file if there isn't one!");
  848.         usage();
  849.     }
  850.     ok = process_stdin(base_cpp_cmd);
  851.     }    
  852.     else
  853.     for (i = optind; i < argc; ++i)
  854.         if (!(ok = process_file(base_cpp_cmd,argv[i])))    break;
  855.  
  856.     if (ok && firstpage)
  857.     output_manual_pages(firstpage,argc - optind, link_type);
  858.     free_manual_pages(firstpage);
  859.     destroy_enum_lists();
  860.  
  861.     if (cpp_opts)    free((char *)base_cpp_cmd);
  862.  
  863.     for (includefile = first_include; includefile;)
  864.     {
  865.     IncludeFile *next = includefile->next;
  866.     free(includefile);
  867.     includefile = next;
  868.     }
  869.  
  870.     for (excludesection = first_excluded_section; excludesection;)
  871.     {
  872.     ExcludeSection *next = excludesection->next;
  873.     free(excludesection);
  874.     excludesection = next;
  875.     }
  876.  
  877.     for (i = 0; i < _OBJECT_NUM; i++)
  878.     {
  879.     safe_free(output_object[i].subdir);
  880.     safe_free(output_object[i].extension);
  881.     }
  882.  
  883. #ifdef DBMALLOC
  884.     malloc_dump(2);
  885.     malloc_chain_check(1);
  886. #endif
  887. #ifdef MALLOC_DEBUG
  888.     sleep(1000000);
  889. #endif
  890.     return !ok;
  891. }
  892.